
const fs = require('fs')
const request = require('request')

module.exports = {
  // 下载文件列表
  downloadByPath ({ path, callback, dir, isReDownload }) {
    fs.readFile(path, (err, res) => {
      if (/\[/.test(res.toString())) {
        res = JSON.parse(res)
      } else {
        res = res.toString().split('\n').filter(item => {
          return !!item
        }).map(url => {
          return { url }
        })
      }
      const len = res.length - 1
      // 记录当前下载到第几项
      let index = 0
      // 存储下载成功/失败的图片链接地址
      let successList = [], failList = []
      // 递归函数，使用递归循环防止请求阻塞
      const download = () => {
        //如果不是JSON数据修改此
        let url = res[index].url
        if (index <= len) {
          // 使用try抛出异常，防止因为一张图片下载失败，从而导致后面无法继续下载
          try {
            const fpath = (/path=([^&]+)/.exec(url) || [])[1]
            let downloadPath = dir || './'
            if (fpath) {
              downloadPath = downloadPath + '/' + fpath.replace(/^\//, '')
            }
            this.downloadFile({
              url: url,
              dir: downloadPath,
              isReDownload,
              callBack: (type) => {
                if (type) {
                  console.log(`第${index + 1}个文件下载成功：${url}`)
                  successList.push(url)
                  download()
                  index++
                } else {
                  console.log(`第${index + 1}个文件下载失败!`)
                  failList.push(url)
                  index++
                  download()
                }
              }
            })
          } catch(e) {
            console.log(e)
            console.log("请求失败，当前下载到第" + (index + 1) + "文件")
            failList.push(url)
            index++
            download()
          }
        } else {
          console.log("所有文件下载完成")
          callback({ success: successList, fail: failList })
        }
      }
      download()
    })
  },

  // 下载文件
  async downloadFile ({url, dir, callBack, isReDownload}) {
    let dirPath = dir.replace(/[\/\\]([^\/\\]+)?$/, '')
    // 查看文件夹是否存在
    await fs.stat(dirPath, async (err, stats) => {
      // 如果文件夹不存在，创建文件夹
      if (!stats) await fs.mkdir(
        dirPath,
        { recursive: true },
        mkdirErr => console.log(mkdirErr == null ? "文件夹创建成功" : mkdirErr)
      )
      // 获取图片名称与格式
      const fileName = url.split('/').pop()
      if (dir.split('/').length - 1 != '') dir += '/'
      let targetFile = dir + fileName
      if (/\.\w+/i.test(dir)) {
        targetFile = dir
      }
      // 文件已经下载过
      if (isReDownload !== false && fs.existsSync(targetFile)) {
        callBack(true)
        return true
      }
      // 创建一个文件可写流
      const writeStream = await fs.createWriteStream(targetFile)
      // 使用request创建一个HTTP请求
      const options = this.getOptions({url: encodeURI(url)})
      let readStream = await request(options)
      // 创建一个streams流（个人理解为一个文件流的传输管道）
      /* pipe管道事件
      1、data：从可读流中读取新数据时触发。
      2、end：当可读流中没有数据时触发。
      3、finish：当可写流结束且所有挂起的写入都已完成时发出。
      4、close：一般在流完全关闭时发出，stream有可能不会触发事件。
      5、puse：暂停一个可读流，不常用
      6、resume：重启一个可读流。
      */
      await readStream.pipe(writeStream).on('end', (r) => writeStream.end())
      //当本地文件写入结束后触发finish
      await writeStream.on('finish', () => callBack(true)).on('error', () => {
        callBack(false)
      })
    })
  },
  // 获取请求配置
  getOptions ({ url }) {
    var ip = this.getIp() // 随机生成IP迷惑服务器
    var agent = this.getAgent() // 随机生成浏览器信息
    var options = {
      method: 'GET',
      url: url,
      headers: {
        'User-Agent': agent,
        'X-Forwarded-For': ip,
        'Connection': 'keep-alive'
      },
      timeout: 5000,
      forever: true
    }
    return options
  },
  // 获取IP
  getIp () {
    return Math.floor(Math.random() * 256) // 随机生成IP迷惑服务器
    + '.' + Math.floor(Math.random() * 256)
    + '.' + Math.floor(Math.random() * 256)
    + '.' + Math.floor(Math.random() * 256)
  },
  // 获取浏览器
  getAgent () {
    // 浏览器信息
    const agents = [
      'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60',
      'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0',
      'Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10',
      'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2',
      'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36',
      'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
      'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16',
      'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36',
      'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko',
      'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11',
      'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER',
      'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER)',
      'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E; LBBROWSER)',
      'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400)',
      'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)',
      'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 SE 2.X MetaSr 1.0',
      'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; SE 2.X MetaSr 1.0)',
      'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/4.4.3.4000 Chrome/30.0.1599.101 Safari/537.36',
      'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 UBrowser/4.0.3214.0 Safari/537.36'
    ]
    const agent = Math.floor(Math.random() * agents.length) // 随机生成浏览器信息
    return agent
  }
}




